package com.cloudbroker.bcs.platform.dav.middle.bizservice.impl;

import static com.alibaba.fastjson.JSON.parseObject;
import static com.alibaba.fastjson.JSON.toJavaObject;
import static com.cloudbroker.bcs.common.util.ValueUtil.getString;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.GET_ACCESS_TOKEN;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.GET_ACCESS_TOKEN_BY_CODE;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.GET_ALL_OPENID;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.GET_TICKET;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.GET_TICKET_DBZQ;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.GET_USERINFO_BY_ACCESS_TOKEN;
import static com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatUrl.SEND_MESSAGE;
import static com.cloudbroker.bcs.platform.dav.common.config.ConfigValues.getWeixinAppKey;
import static com.cloudbroker.bcs.platform.dav.common.config.ConfigValues.getWeixinAppSecret;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cloudbroker.bcs.common.constants.BasicFields;
import com.cloudbroker.bcs.common.entity.HSBCPSBackVO;
import com.cloudbroker.bcs.common.util.CollectionUtil;
import com.cloudbroker.bcs.common.util.DateTimeUtil;
import com.cloudbroker.bcs.common.util.MD5Util;
import com.cloudbroker.bcs.common.util.OrderNumberUtil;
import com.cloudbroker.bcs.common.util.StringUtil;
import com.cloudbroker.bcs.common.util.VOUtil;
import com.cloudbroker.bcs.common.util.ValueUtil;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.HSBCPSErrorCodes.PayErr;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.HSBCPSErrorCodes.WechatShareErr;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.WechatConstant;
import com.cloudbroker.bcs.platform.dav.bizapi.constants.status.RechargeStatus;
import com.cloudbroker.bcs.platform.dav.bizapi.service.base.vo.PageVO;
import com.cloudbroker.bcs.platform.dav.bizapi.service.business.wechat.vo.PayForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.WeixinBizService;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.GetAccessTokenForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.GetTicketForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.GetUserInfoByAccessTokenForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.GetUserInfoByCodeForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.MassMessageForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.SaveLoginInformationForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.request.SendWxMessageForm;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.response.GetAccessTokenBackVo;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.response.GetHisMessageBackResult;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.response.GetHisMessageBackVo;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.response.GetTicketBackVo;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.response.GetUserInfoBackVo;
import com.cloudbroker.bcs.platform.dav.bizapi.service.export.vo.response.TongLianPayBackVo;
import com.cloudbroker.bcs.platform.dav.common.config.ConfigValues;
import com.cloudbroker.bcs.platform.dav.common.constant.IFSField;
import com.cloudbroker.bcs.platform.dav.common.util.HttpUtil;
import com.cloudbroker.bcs.platform.dav.middle.context.HSBCPSBizDataContext;
import com.cloudbroker.bcs.platform.dav.middle.entity.LoginLog;
import com.cloudbroker.bcs.platform.dav.middle.entity.MassMessage;
import com.cloudbroker.bcs.platform.dav.middle.entity.RechargeWater;
import com.cloudbroker.bcs.platform.dav.middle.service.LoginLogService;
import com.cloudbroker.bcs.platform.dav.middle.service.MassMessageService;
import com.cloudbroker.bcs.platform.dav.middle.service.RechargeWaterService;
import com.cloudbroker.bcs.platform.dav.middle.util.HttpsUtil;
import com.cloudbroker.bcs.platform.dav.middle.util.PositionStrUtil;

import cz.mallat.uasparser.OnlineUpdater;
import cz.mallat.uasparser.UASparser;
import cz.mallat.uasparser.UserAgentInfo;

/**
 * Created by xuyn15828 on 2016/5/12.
 */
@Service
public class WeixinBizServiceImpl implements WeixinBizService {
    
    private static final Logger logger = LoggerFactory.getLogger(WeixinBizServiceImpl.class);
    
    @Resource
    private RechargeWaterService rechargeWaterService;
    
    @Resource
    private MassMessageService massMessageService;
    
    @Resource
    private LoginLogService loginLogService;
    
    @Override
    public GetAccessTokenBackVo getAccessTokenByCode(GetAccessTokenForm form) {
        String appid = getString(form.getAppid(), getWeixinAppKey());
        String secret = getString(form.getSecret(), getWeixinAppSecret());
        form.putAppid(appid).putSecret(secret).setGrant_type(WechatConstant.AUTHORIZATION_CODE);
        JSONObject json = parseObject(HttpUtil.doGet(GET_ACCESS_TOKEN_BY_CODE, form));
        CollectionUtil.transKey(json, IFSField.ERRCODE, BasicFields.EXT_ERROR_NO);
        CollectionUtil.transKey(json, IFSField.ERRMSG, BasicFields.EXT_ERROR_INFO);
        return toJavaObject(json, GetAccessTokenBackVo.class);
    }
    
    @Override
    public GetUserInfoBackVo getUserinfoByAccessToken(GetUserInfoByAccessTokenForm form) {
        JSONObject json = parseObject(HttpUtil.doGet(GET_USERINFO_BY_ACCESS_TOKEN, form));
        CollectionUtil.transKey(json, IFSField.ERRCODE, BasicFields.EXT_ERROR_NO);
        CollectionUtil.transKey(json, IFSField.ERRMSG, BasicFields.EXT_ERROR_INFO);
        return toJavaObject(json, GetUserInfoBackVo.class);
    }
    
    @Override
    public GetUserInfoBackVo getUserinfoByCode(GetUserInfoByCodeForm form) {
        String appid = form.getAppid();
        HSBCPSBizDataContext.setBrokerId(form.getBroker_id());
        if (StringUtil.isEmpty(appid)) {
            appid = getWeixinAppKey();
        }
        String secret = form.getSecret();
        if (StringUtil.isEmpty(secret)) {
            secret = getWeixinAppSecret();
        }
        form.putAppid(appid).putSecret(secret).setGrant_type(WechatConstant.AUTHORIZATION_CODE);
        JSONObject json = parseObject(HttpUtil.doGet(GET_ACCESS_TOKEN_BY_CODE, form));
        GetUserInfoByAccessTokenForm param = toJavaObject(json, GetUserInfoByAccessTokenForm.class).putLang(
                WechatConstant.zh_CN);
        return getUserinfoByAccessToken(param);
    }
    
    @Override
    public GetUserInfoBackVo getUserinfoByCodeTenant(GetUserInfoByCodeForm form) {
        String appid = form.getAppid();
        Integer tenantId = Integer.parseInt(form.getTenant_id());
        if (StringUtil.isEmpty(appid)) {
            appid = ConfigValues.getWxAppKeyByTenant(tenantId);
        }
        String secret = form.getSecret();
        if (StringUtil.isEmpty(secret)) {
            secret = ConfigValues.getWxAppSecretByTenant(tenantId);
        }
        form.putAppid(appid).putSecret(secret).setGrant_type(WechatConstant.AUTHORIZATION_CODE);
        JSONObject json = parseObject(HttpUtil.doGet(GET_ACCESS_TOKEN_BY_CODE, form));
        GetUserInfoByAccessTokenForm param = toJavaObject(json, GetUserInfoByAccessTokenForm.class).putLang(
                WechatConstant.zh_CN);
        return getUserinfoByAccessToken(param);
    }
    
    @Override
    public GetAccessTokenBackVo getAccessToken(GetAccessTokenForm form) {
        if (StringUtil.isBlank(form.getAppid()) || StringUtil.isBlank(form.getSecret())) {
            form.putAppid(getWeixinAppKey()).putSecret(getWeixinAppSecret())
                    .putGrant_type(WechatConstant.CLIENT_CREDENTIAL);
        }
        JSONObject json = parseObject(HttpUtil.doGet(GET_ACCESS_TOKEN, form));
        CollectionUtil.transKey(json, IFSField.ERRCODE, BasicFields.EXT_ERROR_NO);
        CollectionUtil.transKey(json, IFSField.ERRMSG, BasicFields.EXT_ERROR_INFO);
        return toJavaObject(json, GetAccessTokenBackVo.class);
    }
    
    @Override
    public GetTicketBackVo getTicket(GetTicketForm form) {
        Integer tenant_id = StringUtil.isBlank(form.getTenant_id()) ? -1 : Integer.parseInt(form.getTenant_id());
        GetAccessTokenForm getAccessTokenForm = new GetAccessTokenForm();
        getAccessTokenForm.setAppid(ConfigValues.getWxAppKeyByTenant(tenant_id));
        getAccessTokenForm.setSecret(ConfigValues.getWxAppSecretByTenant(tenant_id));
        getAccessTokenForm.setGrant_type(WechatConstant.CLIENT_CREDENTIAL);
        switch (ConfigValues.getWxTicketImpltype(tenant_id)) {
            case "common": {
                HSBCPSBizDataContext.setBrokerId(form.getBroker_id());
                GetAccessTokenBackVo accessTokenBackVo = getAccessToken(getAccessTokenForm);
                if (accessTokenBackVo == null || StringUtil.isBlank(accessTokenBackVo.getAccess_token())) {
                    return null;
                }
                form.putType(WechatConstant.JSAPI);
                form.setAccess_token(accessTokenBackVo.getAccess_token());
                JSONObject json = parseObject(HttpUtil.doGet(GET_TICKET, form));
                CollectionUtil.transKey(json, IFSField.ERRCODE, BasicFields.EXT_ERROR_NO);
                CollectionUtil.transKey(json, IFSField.ERRMSG, BasicFields.EXT_ERROR_INFO);
                return toJavaObject(json, GetTicketBackVo.class);
            }
            case "dbzq": {
                Map<String, Object> map = null;
                GetTicketBackVo getTicketBackVo = new GetTicketBackVo();
                JSONObject json = parseObject(HttpUtil.doGet(GET_TICKET_DBZQ, map));
                if (!json.isEmpty() && "success".equals(json.get(IFSField.ERRCODE_DBZQ))) {
                    JSONObject result = parseObject(String.valueOf(json.get("result")));
                    getTicketBackVo.setExpires_in(Integer.parseInt(String.valueOf(result.get("last_ticket_date"))));
                    getTicketBackVo.setTicket(String.valueOf(result.get("jsapiticket")));
                    return getTicketBackVo;
                }
                return null;
            }
            default:
                return null;
        }
    }
    
    @Override
    public TongLianPayBackVo unifiedorder(PayForm form) {
        Long customer_id = HSBCPSBizDataContext.getCustomer().getCustomer_id();
        TongLianPayBackVo vo = new TongLianPayBackVo();
        TreeMap<String, Object> treeMap = initData(form);
        String url = "https://vsp.allinpay.com/apiweb/weixin/pay";
        Map<String, String> res = (Map) JSONObject.parse(HttpUtil.doPost(url, (Map) treeMap));
        String error_no = res.get("retcode");
        if ("SUCCESS".equals(error_no)) {
            vo.setCusid(res.get("cusid"));
            vo.setAppid(res.get("appid"));
            vo.setTrxid(res.get("trxid"));
            vo.setChnltrxid(res.get("chnltrxid"));
            vo.setReqsn(res.get("reqsn"));
            vo.setRandomstr(res.get("randomstr"));
            vo.setTrxstatus(res.get("trxstatus"));
            vo.setErrmsg(res.get("errmsg"));
            vo.setFintime(res.get("fintime"));
            vo.setWeixinstr(res.get("weixinstr"));
            vo.setSign(res.get("sign"));
            //创建流水
            RechargeWater rw = new RechargeWater();
            rw.setCustomer_id(customer_id);
            rw.setRecharge_rmb(new BigDecimal(form.getTrxamt()));
            rw.setRecharge_amount(ValueUtil.getInt(form.getTrxamt(), 0) / 10);
            rw.setCharge_status(RechargeStatus.ERR.getVal());
            rw.setCharge_status_mean("订单待处理");
            rw.setCharge_type(1);
            rw.setCharge_channel_mean("微信公众号支付");
            rw.setCreate_time(new Date());
            rw.setTransaction_no(vo.getTrxid());
            rw.setTrans_id(vo.getReqsn());
            rechargeWaterService.save(rw);
        } else {
            logger.info("金币充值失败----------->" + res.get("retmsg") + "<-------------");
            return VOUtil.genErrorResult(PayErr.GOLDCOIN_CHANGE_ERR, TongLianPayBackVo.class);
        }
        return VOUtil.setSuccessResult(vo);
    }
    
    @Override
    public HSBCPSBackVO massMessage(MassMessageForm form) {
        String[] appid = ConfigValues.getWeixinMassAppKey().split(",");
        String[] appkey = ConfigValues.getWeixinMassAppSecret().split(",");
        for (int i = 0; i < appid.length; i++) {
            GetAccessTokenBackVo accessTokenBackVo = getAccessToken(new GetAccessTokenForm().putAppid(appid[i])
                    .putSecret(appkey[i]).putGrant_type(WechatConstant.CLIENT_CREDENTIAL));
            if (StringUtil.isBlank(accessTokenBackVo.getAccess_token())) {
                return VOUtil.genErrorResultVo(WechatShareErr.AUTH_FAILED);
            }
            String accessToken = accessTokenBackVo.getAccess_token();
            List<String> list = getAllOpenid(accessToken);
            massMessageService.asyncMass(list, accessToken, form, HSBCPSBizDataContext.getBroker().getBroker_id(),
                    HSBCPSBizDataContext.getTenantId());
        }
        return VOUtil.genSuccessBackVo();
    }
    
    @Override
    public GetHisMessageBackResult funcGetHisMessage(PageVO form) {
        GetHisMessageBackResult vo = new GetHisMessageBackResult();
        Integer pageNo = ValueUtil.getInt(form.getPage_no(), 1);
        Integer pageSize = ValueUtil.getInt(form.getPage_count(), ConfigValues.getRequestNum());
        List<MassMessage> list = massMessageService.getAllByBroker(HSBCPSBizDataContext.getBroker().getBroker_id(),
                (pageNo - 1) * pageSize, pageSize);
        List<GetHisMessageBackVo> resList = new ArrayList<>();
        for (MassMessage massMessage : list) {
            GetHisMessageBackVo getHisMessageBackVo = new GetHisMessageBackVo();
            getHisMessageBackVo.setTitle(massMessage.getTitle());
            getHisMessageBackVo.setDescription(massMessage.getDescription());
            getHisMessageBackVo.setUrl(massMessage.getUrl());
            getHisMessageBackVo.setSuccess_num(massMessage.getSuccess_num());
            getHisMessageBackVo.setFail_num(massMessage.getFail_num());
            getHisMessageBackVo.setRefuse_num(massMessage.getRefuse_num());
            getHisMessageBackVo.setSend_time(massMessage.getSend_time());
            resList.add(getHisMessageBackVo);
        }
        vo.setCount(massMessageService.getCount(HSBCPSBizDataContext.getBroker().getBroker_id()));
        vo.setData_list(resList);
        return VOUtil.setSuccessResult(vo);
    }
    
    @Override
    public HSBCPSBackVO funcSaveLoginInformation(SaveLoginInformationForm form) {
        UASparser uasParser = null;
        try {
            uasParser = new UASparser(OnlineUpdater.getVendoredInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        HSBCPSBackVO vo = new HSBCPSBackVO();
        LoginLog loginLog = new LoginLog();
        //1代表粉丝，2代表大V
        loginLog.setUser_type("1");
        loginLog.setUser_id(HSBCPSBizDataContext.getCustomer().getCustomer_id());
        try {
            if (null != uasParser) {
                UserAgentInfo userAgentInfo = uasParser.parse(form.getBrowser());
                loginLog.setOperating_system(userAgentInfo.getOsName());
                loginLog.setBrowser(userAgentInfo.getUaName());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        loginLog.setPhone_login_flag(HttpUtil.getPhoneFlag(form.getBrowser()));
        loginLog.setLogin_time(DateTimeUtil.toString(new Date()));
        loginLog.setRemote_ip(form.getIp());
        loginLog.setLogin_address(HttpUtil.getAddressByIp(form.getIp()));
        loginLog.setMobile(HSBCPSBizDataContext.getCustomer().getMobile());
        loginLog.setWx_open_id(HSBCPSBizDataContext.getCustomer().getWx_open_id());
        loginLogService.save(loginLog);
        return VOUtil.setSuccessResult(vo);
    }
    
    @Override
    public HSBCPSBackVO funcSendWxMessage(SendWxMessageForm form) {
        HSBCPSBackVO vo = new HSBCPSBackVO();
        GetAccessTokenBackVo accessTokenBackVo = getAccessToken(new GetAccessTokenForm().putAppid(form.getAppid())
                .putSecret(form.getSecret()).putGrant_type(WechatConstant.CLIENT_CREDENTIAL));
        if (StringUtil.isBlank(accessTokenBackVo.getAccess_token())) {
            return VOUtil.genErrorResultVo(WechatShareErr.AUTH_FAILED);
        }
        String url = SEND_MESSAGE + "?access_token=" + accessTokenBackVo.getAccess_token();
        String muban = "'{'\"touser\":\"{0}\",\"msgtype\":\"news\",\"news\":'{'\"articles\": ['{'\"title\":\"{1}\",\"description\":\"{2}\",\"url\":\"{3}\"'}']'}''}'";
        String title = "助力成功召唤，iphone7";
        String describe = "恭喜您成功邀请好友助力，又获得1次玩游戏赢Iphone7的机会！每颗星星暗藏奖品，购物券、话费等更多大奖拿到手软~快快点击进入游戏吧。";
        String activityUrl = "https://fans.yjifs.com/index.php";
        String[] array = new String[] { form.getOpenid(), title, describe, activityUrl };
        String text = MessageFormat.format(muban, array);
        JSONObject jsonObject = HttpsUtil.post(url, text, "UTF-8");
        if (!"0".equals(String.valueOf(jsonObject.get("errcode")))) {
            return VOUtil.genErrorResultVo(WechatShareErr.AUTH_FAILED);
        }
        return VOUtil.setSuccessResult(vo);
    }
    
    private List<String> getAllOpenid(String accessToken) {
        List<String> list = new ArrayList<>();
        Map<String, Object> params = new HashMap<>();
        params.put("access_token", accessToken);
        params.put("next_openid", "");
        int num = 0;
        while (true) {
            Map<String, Object> map = (Map) JSONObject.parse(HttpUtil.doGet(GET_ALL_OPENID, params));
            Map<String, Object> data = (Map) map.get("data");
            for (Object str : (JSONArray) data.get("openid")) {
                list.add((String) str);
            }
            num += Integer.parseInt(map.get("count") + "");
            if (num >= Integer.parseInt(map.get("total") + "")) {
                break;
            }
            params.put("next_openid", map.get("next_openid"));
        }
        return list;
    }
    
    private TreeMap<String, Object> initData(PayForm form) {
        Long broker_id = HSBCPSBizDataContext.getBrokerId();
        TreeMap<String, Object> treeMap = new TreeMap<>();
        treeMap.put("cusid", ConfigValues.getTongLianCID());
        treeMap.put("appid", ConfigValues.getTongLianId());
        treeMap.put("key", ConfigValues.getTongLianKey());
        treeMap.put("body", form.getDesc());
        treeMap.put("openid", form.getOpenid());
        treeMap.put("reqsn",
                PositionStrUtil.getPositionStr() + OrderNumberUtil.encode(broker_id == null ? 0L : broker_id));
        treeMap.put("trxamt", form.getTrxamt().toString());
        treeMap.put("randomstr", UUID.randomUUID().toString().trim().replaceAll("-", ""));
        treeMap.put("paytype", "1");
        treeMap.put("notify_url", ConfigValues.getNotifyUrl());
        treeMap.put("sign", MD5Util.encrypt(MD5Util.dictSortTL(treeMap)));
        return treeMap;
    }
    
}
